﻿// Inner Fire 游戏引擎库
// GameObject - 游戏对象
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用层（4）
// 游戏最基础的对象，所有和模型有关的对象都继承自此类
// 也许在这个上面还要有一个更加基础的Object类。用于管理所有元素。
// 比如UI的Object也是需要一个GameObject。
// 但目前暂时这样。到时候看情况再进行重构。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-01-21

#pragma once

#include <game/component/component.h>
#include <game/object/transform.h>
#include <memory>
#include <static_string.h>
#include <game/physics/rigid_body.h>
#include <EASTL/unordered_map.h>

namespace ifire::dx {
class SkinAnimator;
}

namespace ifire::game {
class Scene;
class AnimationClip;
class Armature;
class RigidBody;

class GameObject {
public:
  GameObject(ikit::sstr name, Scene* scene, GameObject* parent = nullptr);
  GameObject(const GameObject& lhs) = delete;
  GameObject& operator=(const GameObject& lhs) = delete;
  // 必须是虚析构函数，不然在释放指针的时候，会导致只能释放基类的内容
  virtual ~GameObject();

  // 常规控制更新
  virtual void FixedUpdate();
  // 延迟更新
  virtual void LateUpdate();

  // 返回此对象的骨架。如果没有，则返回nullptr
  virtual Armature* GetArmature();
  // 返回蒙皮骨骼的Animator，如果没有，则返回nullptr
  virtual dx::SkinAnimator* GetSkinAnimator();

  // 打印信息
  virtual void PrintInfo(ikit::sstr info_type);
  // 更新Transform，因为每个项目的RenderItem都不一样，所以这里需要继承者来处理
  virtual void UpdateTransform();
  // 直接设置最终的变换矩阵
  virtual void SetRenderMatrix(FMat mat);

  // 根据名称增加一个组件（这个不是很灵活，但是目前暂时这样吧）
  Component* AddComponent(ikit::sstr component_type);
  // 为对象增加一个组件，注意这里将移交unique_ptr的控制。
  Component* AddComponent(ComponentPtr comp);
  // 按类型获得一个组件
  Component* GetComponent(ikit::sstr component_type);

  // 为项目增加RigidBody
  RigidBody* AddRigidBody();
  // 为项目增加一个碰撞体
  Collider* AddCollider();

  // 使用Transform的快捷方式，设置位置
  void SetPosition(IVec3 position);
  // 使用Transform的快捷方式，设置旋转，值为欧拉角（角度）
  void SetRotation(IVec3 rotation);
  // 使用Transform的快捷方式，设置缩放
  void SetScale(IVec3 scale);

  // 挂载Lua对象
  void AttachLuaObject(ikit::sstr name, int register_index);
  // 获得Lua对象
  int GetLuaObject(ikit::sstr name);

  //
  // 属性访问
  //
  GameObject* Parent() const { return parent_; }
  void SetParent(GameObject* parent);
  Transform& GetTransform() { return transform_; }
  void SetName(ikit::sstr name) { name_ = name; }
  const ikit::sstr GetName() { return name_; }
  RigidBody* GetRigidBody() { return rigid_body.get(); }
  Collider* GetCollider() { return collider.get(); }
  uint64_t GetUID() const { return uid; }


protected:
  // 对象的名称
  ikit::sstr name_;
  // 对象的UniqueID
  std::uint64_t uid;
  // 对象所属的场景
  Scene* scene_;
  // 对象的父级
  GameObject* parent_;
  // 项目的Transform
  Transform transform_;
  // 项目的子项
  eastl::vector<GameObject*> children;
  // 项目的组件
  eastl::vector<ComponentPtr> components_;
  
  // 此项目的RigidBody(直接可访问）
  std::unique_ptr<RigidBody> rigid_body;
  // 此项目的碰撞体
  std::unique_ptr<Collider> collider;
  // 用于保存Lua中挂载的对象
  eastl::unordered_map<size_t, int> lua_objects_;
};

using GameObjectPtr = std::unique_ptr<GameObject>;

} // namespace ifire::game